#!/usr/bin/env python
# -*- coding: utf8 -*-
# title       :
# description :
# author      :'ShenMeng'


from PySide import QtGui, QtCore
import math
import yaml
import maya.cmds as cmds
import shutil
import os
import sys
from . import resources_rc

class ConfigError(Exception):
    def __init__(self, parent):
        super(ConfigError, self).__init__(parent)
        
class DataError(Exception):
    def __init__(self, parent):
        super(DataError, self).__init__(parent)

class Smpublish(QtGui.QDialog):
    def __init__(self, config, parent=QtGui.QApplication.activeWindow()):
        super(Smpublish, self).__init__(parent=parent)
        self._step = config
        self._hooks_path = ''
        self._pre_publish_hooks = []
        self._post_publish_hooks = []
        self._publish_hooks = []

        self.main_layout = QtGui.QVBoxLayout()
        self.main_layout.setSpacing(0)
        
        self.item_label = QtGui.QLabel('aaaaaaa')
        self.setMinimumSize(400,110)
        self.setMaximumSize(400,110)
        
        self.progress_bar = QtGui.QProgressBar()
        self.progress_bar.setTextVisible(0)
        self.setStyleSheet("""
        QProgressBar, QTextEdit{border:none;background:rgba(0,0,0,0);}
        QProgressBar{border:none;}
        QProgressBar::chunk{background:rgb(0, 140, 210);border:none;}
        """)

        self.progress_bar.setMinimumWidth(378)
        self.info_icon = QtGui.QLabel()
        
        self.info_icon.setMaximumSize(70,70)
        self.info_icon.setScaledContents(1)
        self.info_icon.setHidden(1)
        #self.info_label = QtGui.QTextEdit()#QtGui.QLabel()
        #self.info_label.setReadOnly(1)
        self.info_label = QtGui.QLabel()
        #self.info_label.adjustSize()
        
        self.info_label.setHidden(1)
        #self.info_label.setWordWrap(True)

        self.info_layout = QtGui.QHBoxLayout()
        self.info_layout.setContentsMargins(0,0,0,0)
        self.info_layout.addItem(QtGui.QSpacerItem(0,0,QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
        self.info_layout.addWidget(self.progress_bar)
        self.info_layout.addWidget(self.info_icon)
        self.info_layout.addWidget(self.info_label)
        self.info_layout.addItem(QtGui.QSpacerItem(0,0,QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
        
        self.close_layout = QtGui.QHBoxLayout()
        self.close_layout.setContentsMargins(0,0,0,0)
        self.close_btn = QtGui.QPushButton("ok")
        self.close_btn.setHidden(1)
        #self.close_btn.setFlat(1)
        self.close_btn.clicked.connect(self.close)
        self.close_layout.addItem(QtGui.QSpacerItem(20,20,QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum))
        self.close_layout.addWidget(self.close_btn)
        
        self.main_layout.addWidget(self.item_label)
        self.main_layout.addLayout(self.info_layout)
        self.main_layout.addLayout(self.close_layout)
        
        self.setLayout(self.main_layout)
        self.updata_cmd = QtGui.QApplication.instance().processEvents
        
        # 
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.run)
        self.timer.setSingleShot(True)
        #self.timer.start()
        #"""
        # 设置窗体样式
        self.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowSystemMenuHint)
        self._move = False
        self._padding = 5
        self.SHADOW_WIDTH=0   #边框距
        self.isLeftPressDown = False #鼠标左键是否按下
        self.dragPosition=0     #拖动时坐标
        self.Numbers = self.enum(UP=0, DOWN=1, LEFT=2, RIGHT=3, LEFTTOP=4, LEFTBOTTOM=5, RIGHTBOTTOM=6, RIGHTTOP=7, NONE=8) #枚举参数
        self.dir=self.Numbers.NONE #初始鼠标状态
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setMouseTracking(True)
        #"""

    @staticmethod
    def parse_yaml_file(file_path):
        data = None
        with open(str(file_path)) as f:
            data = yaml.load(f)
        return data
        
    def _initData(self):
        try:
            #configFile = 'D:\work\publish_config.yml'
            configPath = os.getenv("Smpublish_CONFIG_PATH")
            configFile = os.path.join(configPath, self._step)
        except Exception, e:
            raise ConfigError('\nConfigError:\n%s' % e)
        
        if os.path.isfile(configFile):
            try:
                data = self.parse_yaml_file(configFile)
                self._publish_path = data['publish_path']
                structure = data['structure']
                self._filename = structure['filename']
                if not self._filename:
                    self._level = int(data['structure']['level']) 
                hooks_data = data.get('hooks')
                if hooks_data:
                    self._hooks_path = hooks_data.get('path', '')
                    publish_hooks = hooks_data.get('publish', None)
                    if publish_hooks and isinstance(publish_hooks, list):
                        self._publish_hooks = publish_hooks
                    pre_hooks = hooks_data.get('pre_publish', None)
                    post_hooks = hooks_data.get('post_publish', None)
                    if isinstance(pre_hooks, list):
                        self._pre_publish_hooks = pre_hooks
                    if isinstance(post_hooks, list):
                        self._post_publish_hooks = post_hooks
                    sys.path.append(self._hooks_path)
                if not os.path.isdir(self._publish_path):
                    os.makedirs(self._publish_path)
            except Exception, e:
                raise DataError('\nDataError>>\n%s' % e)
        else:
            raise ConfigError('\nConfigError>>\nconfig file "%s" is not exists!' % configFile)

        
    @staticmethod
    def get_handle(name):
        try:
            del sys.modules[name]
        except:pass
        handle = __import__(name)
        return handle

    def get_out_path(self):
        out_path = []
        file_path = cmds.file(q=1, sn=1)
        if not os.path.isfile(file_path):
            raise IOError('Current scene has not save yet !')
        base_name = os.path.basename(file_path)
        if self._filename:
            file_name = os.path.splitext(base_name)[0]
            name_part = file_name.split('_')
            name_part.append(base_name)
            out_path = os.path.join(self._publish_path, *name_part)
        else:
            dir_name = os.path.dirname(file_path)
            dir_name.replace('\\','/')
            dir_part = dir_name.split('/')
            dir_part.append(base_name)
            result_part = dir_part[-(self._level+1):]
            if len(dir_part) <= self._level:
                raise DataError("\nDataError>>\n can not pase the out path! place check the file path is math the level set in config file !")
            out_path = os.path.join(self._publish_path, *result_part)
        return out_path.replace('\\', '/')
            
        
    def get_prepublish_handles(self):
        handles = []
        if self._pre_publish_hooks:
            for hook in self._pre_publish_hooks:
                handles.append(self.get_handle(hook))
        return handles
        
    def get_postpublish_handles(self):
        handles = []
        if self._post_publish_hooks:
            for hook in self._post_publish_hooks:
                handles.append(self.get_handle(hook))
        return handles
        
    def get_publish_handles(self):
        handles = []
        if self._post_publish_hooks:
            for hook in self._post_publish_hooks:
                handles.append(self.get_handle(hook))
        return handles
        
    def publish(self, out_path):
        self.item_label.setText('Publish')
        self.progress_bar.reset()
        self.progress_bar.setRange(0,4)
        self.updata_cmd()
        cmds.file(save=1)
        self.progress_bar.setValue(1)
        self.updata_cmd()
        file_path = cmds.file(q=1, sn=1)
        if os.path.isfile(out_path):
            os.remove(out_path)
        self.progress_bar.setValue(2)
        save_folder = os.path.dirname(out_path)
        if not os.path.exists(save_folder):
            os.makedirs(save_folder)
        self.updata_cmd()
        self.progress_bar.setValue(3)
        self.updata_cmd()
        shutil.copy2(file_path, out_path)
        self.progress_bar.setValue(4)
        self.updata_cmd()
        
    def run_handles(self, handles, item):
        self.updata_cmd()
        #hooks = self.getPrepublishHooks()
        self.item_label.setText(item)
        self.progress_bar.reset()
        if handles:
            count = len(handles)
            self.progress_bar.setRange(0, count)
            for index, handle in enumerate(handles):
                self.updata_cmd()
                handle.main()
                self.progress_bar.setValue(index+1) 
        else:
            self.progress_bar.setRange(0,1)
            self.progress_bar.setValue(1)
        
    def run(self):
        try:
            self._initData()
            out_path = self.get_out_path()
            pre_handles = self.get_prepublish_handles()
            self.run_handles(pre_handles, "Prepublish")
            self.publish(out_path)
            post_handles = self.get_postpublish_handles()
            self.run_handles(post_handles, "Postpublish")
        except ConfigError, e:
            self.info_icon.setPixmap(":icons/failure.png")
            self.info_label.setText("Config Error !")
            print e
        except DataError, e:
            self.info_icon.setPixmap(":icons/failure.png")
            self.info_label.setText("Data Error !")
            print e
            
        except Exception, e:
            self.info_icon.setPixmap(":icons/failure.png")
            self.info_label.setText("Failure Publish !")
            print("%s\n%s" %("Failure Publish !", e))
            self.updata_cmd()
        else:
            self.info_icon.setPixmap(":icons/success.png")
            self.info_label.setText('Successfull Publish !')
        finally:
            self.info_label.setHidden(0)
            self.item_label.setHidden(1)
            self.progress_bar.setHidden(1)
            self.info_icon.setHidden(0)
            self.close_btn.setHidden(0)
        
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            return

        super(Smpublish, self).keyPressEvent(event)

    def mousePressEvent(self,event):
        if event.button() == QtCore.Qt.LeftButton:
            self._move = True
            self.offset = event.pos()

    def mouseReleaseEvent(self, event):
        self._move = False

    def mouseMoveEvent(self,event):
        if self._move:
            self.move(event.globalPos()-self.offset)
            
    def enum(self, **enums):
        return type('Enum', (), enums) 
        
    def eventFilter(self, source, event):
        return
        if event.type() == QtCore.QEvent.MouseMove:
            if event.buttons() == QtCore.Qt.NoButton:
                gloPoint = event.globalPos()
                self.region(gloPoint)
        return super(Smpublish, self).eventFilter(source, event)

    def paintEvent(self, event):
        wth = 5
        path = QtGui.QPainterPath()
        path.setFillRule(QtCore.Qt.WindingFill)
        path.addRect(wth, wth, self.width() - wth*2, self.height() - wth*2)

        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
        painter.fillPath(path, QtGui.QBrush(QtGui.QColor(60, 60, 60)))
        cc = (0, 170, 230, 255)
        color = QtGui.QColor(0, 140, 210, 255)
        for i in range(wth):
            path = QtGui.QPainterPath()
            path.setFillRule(QtCore.Qt.WindingFill)
            path.addRect(wth - i, wth - i, self.width() - (wth - i) * 2, self.height() - (wth - i) * 2)
            color.setAlpha(255 - math.sqrt(i) * 150)
            painter.setPen(color)
            painter.drawPath(path)
            
    def showEvent(self, event):
        self.timer.start()
        super(Smpublish, self).showEvent(event)
        
    def closeEvent(self, event):
        """
        关闭界面的时候讲hooks路径从系统路径里面移除掉
        Args:
            event:
        Returns:
        """
        if self._hooks_path in sys.path:
            sys.path.remove(self._hooks_path)
        super(Smpublish, self).closeEvent(event)
            
        
if __name__ == "__main__":
    vp = Smpublish(QtGui.QApplication.activeWindow())
    vp.show()